#ifndef AVALON_CODEDREADER_HPP
#define AVALON_CODEDREADER_HPP
#include "Avalon/Base/Handle.hpp"
#include "Avalon/Codecs/Codecs.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/Reader.hpp"

namespace Avalon {
namespace Codecs {

  /*! \class CodedReader
   *  \brief Reads coded data using a Decoder.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class CodedReader : public IO::Reader {
    public:

      //! Constructs a CodedReader.
      /*!
        \param source The source to read from.
        \param decoder The Decoder to use.
      */
      CodedReader(Carry<IO::Reader> source, Decoder* decoder);

      virtual ~CodedReader();

      virtual bool IsAtEndOfDataSource();

      virtual Threading::Async<int>::Ptr Read(IO::Buffer* destination);

      virtual Threading::Async<int>::Ptr Read(void* destination, int size);

      virtual Threading::Async<int>::Ptr Read(IO::Buffer* destination,
        int size);

    private:
      boost::recursive_mutex m_mutex;
      Handle<IO::Reader> m_source;
      boost::scoped_ptr<Decoder> m_decoder;
      IO::Buffer m_initialDestination;
      Threading::Async<int>::Ptr m_sourceRead;

      void OnBufferRead(IO::Buffer* destination,
        const Threading::AsyncOwner<int>::Ptr& decodedRead,
        const Threading::Async<int>::Ptr& sourceRead);
      void OnDataRead(void* destination, int size,
        const Threading::AsyncOwner<int>::Ptr& decodedRead,
        const Threading::Async<int>::Ptr& sourceRead);
  };
}
}

#endif // AVALON_CODEDREADER_HPP
